<template>
  <div
    class="viewer bg-background"
    ref="viewer"
    :class="{ transition: viewerTransitioning, 'bg-black': props.bgBlack }"
    :style="{ transform: viewerTransform, opacity: viewerOpacity }"
    @transitionend="onTransitionEnd"
  >
    <slot></slot>
    <div class="close-icon">
      <Icon size="20" name="close" @click="closeViewer"></Icon>
    </div>
  </div>
</template>
<script setup>
import { computed, ref } from 'vue'
import { useSwipe, whenever } from '@vueuse/core'
import velocityCalculator from '@/utils/velocity-calculator'
import { usePreventTouchmove } from '@/compositions/mobile/preventTouchmove'

const props = defineProps({
  modelValue: { type: Boolean, required: true },
  prevBounds: { type: Object, required: true },
  maxOpacity: { type: Number, default: 1 },
  bgBlack: { type: Boolean, default: false },
})

const emits = defineEmits(['vieweropen', 'viewerclose', 'update:modelValue'])

const viewerTransform = ref('translate(0px, 0px) scale(0, 0)')
const viewerOpacity = ref(0.3)
const viewerTransitioning = ref(false)

const modelValue = computed({
  get: () => props.modelValue,
  set: (val) => emits('update:modelValue', val),
})

whenever(modelValue, openViewer)

function openViewer() {
  if (viewerTransitioning.value) return

  // 初始位置從 bounds 開始
  const { x, y, sx, sy } = props.prevBounds
  setViewerBounds(x, y, sx, sy, 0)

  // transition 至全銀幕
  requestAnimationFrame(() => {
    viewerTransitioning.value = true
    setViewerBounds(0, 0, 1, 1, props.maxOpacity)
  })

  emits('vieweropen')
}
function closeViewer() {
  if (viewerTransitioning.value) return

  // transition 至原先的 bounds 位置
  viewerTransitioning.value = true
  modelValue.value = false
  const { x, y, sx, sy } = props.prevBounds
  setViewerBounds(x, y, sx, sy, 0.5)
}
function onTransitionEnd() {
  viewerTransitioning.value = false
  if (!modelValue.value) {
    setViewerBounds(0, 0, 0, 0, 0)
    emits('viewerclose')
  }
}
function setViewerBounds(x, y, sx, sy, o) {
  viewerTransform.value = `translate(${x}px, ${y}px) scale(${sx}, ${sy})`
  viewerOpacity.value = o
}

// viewer 滑動關閉效果
const viewer = ref(null)
const SWIPE_START_THRESHOLD = 0
const SWIPE_VELOCITY_THRESHOLD = 100
const { abs, floor, max, min } = Math
const { reset: resetX, updatePosition: updatePositionX, getVelocity: getVelocityX } = velocityCalculator()
const { reset: resetY, updatePosition: updatePositionY, getVelocity: getVelocityY } = velocityCalculator()
const { lengthX, lengthY } = useSwipe(viewer, {
  threshold: SWIPE_START_THRESHOLD,
  onSwipe(evt) {
    evt.stopPropagation()
    if (viewerTransitioning.value) return

    const x = floor(lengthX.value)
    const y = floor(lengthY.value)
    const len = floor(max(abs(x), abs(y)) / 10)
    const scale = (100 - min(10, len)) / 100
    updatePositionX(x)
    updatePositionY(y)

    setViewerBounds(-x, -y, scale, scale, 1)
  },
  onSwipeEnd(evt) {
    evt.stopPropagation()

    const len = max(abs(floor(lengthX.value)), abs(floor(lengthY.value)))
    const velocity = max(abs(getVelocityX()), abs(getVelocityY()))
    resetX()
    resetY()

    if (velocity > SWIPE_VELOCITY_THRESHOLD || len > 100) {
      closeViewer()
    } else {
      viewerTransitioning.value = true
      setViewerBounds(0, 0, 1, 1, 1)
    }
  },
})

// 阻止手機上下滑的時候會飄動
usePreventTouchmove(viewer)
</script>
<style scoped lang="scss">
.close-icon {
  position: absolute;
  top: 1rem;
  right: 1rem;
  cursor: pointer;
}

.viewer {
  width: 100%;
  height: 100%;
  position: absolute;
  top: 0;
  left: 0;
  transform-origin: center;
  z-index: 1;

  display: flex;
  justify-content: center;
  align-items: center;

  &.transition {
    transition: transform 0.3s, opacity 0.3s;
  }
}

.bg-black {
  background: rgb(0, 0, 0);
}
</style>
